package com.gange.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gange.annotations.RequiredToken;
import com.gange.entity.Played;
import com.gange.entity.User;
import com.gange.entity.Video;
import com.gange.feignclients.VideosClient;
import com.gange.service.IPlayedService;
import com.gange.service.IUserService;
import com.gange.utils.ImageUtils;
import com.gange.utils.JSONUtils;
import com.gange.utils.OSSUtils;
import com.gange.utils.RedisPrefix;
import com.gange.vo.MsgVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户 前端控制器
 * </p>
 *
 * @author gange
 * @since 2022-07-23
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
    @Autowired
    private IUserService userService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private VideosClient videosClient;
    @Autowired
    private IPlayedService playedService;
    /**
     * 用户登录
     */
    @PostMapping("tokens")
    // MsgVo = phone + captcha 从前端接收的json转为msgvo对象
    public Map<String, Object> tokens(@RequestBody MsgVO msgVO, HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        //1.获取用户手机号
        String phone = msgVO.getPhone();
        //2.获取用户验证码
        String captcha = msgVO.getCaptcha();
        log.info("手机号: {},验证码:{}", phone, captcha);

        String phoneKey = "phone_" + phone;
        //3.根据手机号判断redis中是否还存在该手机号验证码,如果不存在说明验证码已经过期!
        if (!redisTemplate.hasKey(phoneKey)) {
            throw new RuntimeException("提示:验证码已经过期!");
        }

        //4.根据手机号获取redis中验证码
        String redisCaptcha = redisTemplate.opsForValue().get(phoneKey).toString();
        //5.比较用户输入的验证码和redis中验证码是否一致
        if (!StringUtils.equals(captcha, redisCaptcha)) {
            throw new RuntimeException("提示:验证码输入错误!");
        }

        //6.判断是否为首次登录  //判断手机号之前是否登录过
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("phone",phone);
        User user = userService.getOne(wrapper);
        if (ObjectUtils.isEmpty(user)) {
            user = new User();//创建一个用户对象
            user.setName(phone);
            user.setCreatedAt(LocalDateTime.now());//设置创建时间
            user.setUpdatedAt(LocalDateTime.now());//设置更新时间
            user.setPhone(phone); //设置用户的手机号
            user.setIntro("");//设置简介为空
            //初始化默认头像
            user.setAvatar(ImageUtils.getPhoto());//随机初始化头像
            user.setPhoneLinked(true);//是否绑定手机
            user.setWechatLinked(false);//是否绑定微信
            user.setFollowersCount(0);//设置粉丝数
            user.setFollowingCount(0);//设置关注数
            userService.save(user);//保存用户信息
        }

        //7.保存用户登录标记
        String token = request.getSession().getId(); //根据请求sessionid  手机号
        String tokenKey = "session_" + token; //session_xxxxx  session_132...
        log.info("生成token: {}", token);
        //redisTemplate 操作对象  key:对象  value:对象  注意:必须实现对象序列化接口  jdk序列化方式
        //redisTemplate对象中默认序列化方式进行修改: key:String序列化方式   value:json序列化
        redisTemplate.opsForValue().set(tokenKey, user, 7, TimeUnit.DAYS);

        //8.返回token
        result.put("token", token);
        return result;
    }

    /**
     * 已登录的用户信息
     */
    @GetMapping("user")
    @RequiredToken
    public User user(HttpServletRequest request) throws JsonProcessingException {
        User user = (User) request.getAttribute("user");
        log.info("获取的用户信息为: {}", new ObjectMapper().writeValueAsString(user));
        return user;
    }

    /**
     * 注销登录
     */
    @DeleteMapping("tokens")
    public void logout(String token) {
        log.info("当前获获取的token信息: {}", token);
        //1.根据接收token拼接对应TokenKey
        String tokenKey = "session_" + token;
        //2.根据TokenKey在redis中删除
        redisTemplate.delete(tokenKey);
    }

    /**
     * 修改用户信息
     */
    @PatchMapping("user")
    @RequiredToken
    public User user(@RequestBody User user, HttpServletRequest request) {
        //1.获取token信息
        String token = (String) request.getAttribute("token");
        //2.获取原始用户信息
        User userOld = (User) request.getAttribute("user");
        //3.是否修改手机号
        if (!StringUtils.isEmpty(user.getPhone())) {
            //修改手机号
            String phoneKey = "phone_" + user.getPhone();
            if (!redisTemplate.hasKey(phoneKey)) {
                throw new RuntimeException("提示:验证码已过期!");
            }
            String redisCaptcha = redisTemplate.opsForValue().get(phoneKey).toString();//获取redis验证码
            if (!StringUtils.equals(redisCaptcha, user.getCaptcha())) {
                throw new RuntimeException("提示:验证码输入错误!");
            }
            userOld.setPhone(user.getPhone());
        }
        //4.未修改手机号
        if (!StringUtils.isEmpty(user.getName())) {
            userOld.setName(user.getName());
        }
        if (!StringUtils.isEmpty(user.getIntro())) {
            userOld.setIntro(user.getIntro());
        }
        //5.更新用户信息
        userService.updateById(userOld);
        //6.更新redis中原始用户信息
        redisTemplate.opsForValue().set("session_" + token, userOld, 7, TimeUnit.DAYS);
        return userOld;
    }

    /**
     * 用户发布视频
     */
    @PostMapping("/user/videos")
    @RequiredToken
    public Video publishVideos(MultipartFile file, Video video, Integer category_id, HttpServletRequest request) throws IOException {

        //1.获取文件原始名称
        String originalFilename = file.getOriginalFilename();
        log.info("接收文件名称: {}", originalFilename);
        log.info("接收到视频信息: " + new ObjectMapper().writeValueAsString(video));
        log.info("类别id: {}", category_id);
        log.info("文件大小为: {}", file.getSize());

        //2.获取文件后缀 mp4 avi ....
        String ext = FilenameUtils.getExtension(originalFilename);

        //3.生成uuid
        String uuidFileName = UUID.randomUUID().toString().replace("-", "");

        //4.生成uuid文件名名称
        String newFileName = uuidFileName + "." + ext;

        //5.上传阿里云oss 返回文件在oss地址
        String url = OSSUtils.upload(file.getInputStream(), "videos", newFileName);
        log.info("上传成功返回的地址: {}", url);

        //阿里云oss截取视频中某一帧作为封面
        String cover = url + "?x-oss-process=video/snapshot,t_30000,f_jpg,w_0,h_0,m_fast,ar_auto";
        log.info("阿里云oss根据url截取视频封面: {}", cover);

        //6.设置视频信息
        video.setCover(cover);//设置视频封面
        video.setLink(url);//设置视频地址
        video.setCategoryId(category_id);//设置类别id

        //获取用户信息
        User user = (User) request.getAttribute("user");
        video.setUid(user.getId());//设置发布用户id

        //调用视频服务
        Video videoResult = videosClient.publish(video);
        log.info("视频发布成功之后返回的视频信息: {}", JSONUtils.writeValueAsString(videoResult));
        return videoResult;
    }

    /**
     * 视频播放
     */
    @PutMapping("/played/{id}")
    public void played(@PathVariable("id") String videoId, HttpServletRequest request) {
        //redis中播放次数+1
        redisTemplate.opsForValue().increment(RedisPrefix.VIDEO_PLAYED_COUNT_PREFIX + videoId);

        //1.获取登录用户
        User user = getUser(request);
        if (!ObjectUtils.isEmpty(user)) {
            //记录用户的播放历史
            Played played = new Played();
            played.setUid(user.getId());
            played.setVideoId(Integer.valueOf(videoId));
            played.setCreatedAt(LocalDateTime.now());
            played.setUpdatedAt(LocalDateTime.now());
            playedService.save(played);
            log.info("当前用户的播放记录保存成功,信息为: {}", JSONUtils.writeValueAsString(played));
        }
    }

    //根据请求参数中token获取用户信息
    private User getUser(HttpServletRequest request) {
        String token = request.getParameter("token");
        log.info("token为: {}", token);
        String tokenKey = "session_" + token;
        return (User) redisTemplate.opsForValue().get(tokenKey);
    }
}

